package com.hyacinth.server.util;

import com.hyacinth.server.annocation.AuroraAction;
import com.hyacinth.server.annocation.Interceptor;
import com.hyacinth.server.bean.AuroraBeanFactory;
import com.hyacinth.server.config.AbstractConfiguration;
import com.hyacinth.server.config.ApplicationConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.util.*;

/**
 * Function: package Scanner
 *
 * @author crossoverJie
 *         Date: 2018/9/1 11:36
 * @since JDK 1.8
 */
public class ClassScanner {

    private final static Logger LOGGER = LoggerFactory.getLogger(ClassScanner.class);

    private static Set<Class<?>> classes = null;
    private static List<Class<?>> configurationList = null;
    private static Map<String, Class<?>> actionMap = null;
    private static Map<Class<?>, Integer> interceptorMap = null;
    private static Set<AuroraBeanFactory> beanFactoryList = null;


    /**
     * 加载包下面的所有类
     * @param packageName 包名
     * @return 类集合
     */
    public static Set<Class<?>> getClasses(String packageName) {
        if (classes == null){
            classes = new HashSet<>(32) ;
        }
        ClassUtils.loadClassesByPackName(packageName, classes);
        return classes;
    }

    /**
     * 加载包下面的所有配置类
     * @param packageName 包名
     * @return 类集合
     */
    public static List<Class<?>> getConfiguration(String packageName) throws Exception {

        if (configurationList == null) {
            Set<Class<?>> clsList = getClasses(packageName);

            // 增加应用配置类
            clsList.add(ApplicationConfiguration.class) ;

            if (clsList.isEmpty()) {
                return configurationList;
            }

            configurationList = new ArrayList<>(16);
            for (Class<?> cls : clsList) {
                if (cls.getSuperclass() != AbstractConfiguration.class) {
                    continue;
                }
                configurationList.add(cls) ;
            }
        }
        return configurationList;
    }
    /**
     * 获取所有@AuroraAction注解的类
     * @param packageName 包名
     * @return 注解类映射
     */
    public static Map<String, Class<?>> getAuroraAction(String packageName) {

        if (actionMap == null) {
            Set<Class<?>> clsList = getClasses(packageName);

            if (clsList == null || clsList.isEmpty()) {
                return actionMap;
            }

            actionMap = new HashMap<>(16);
            for (Class<?> cls : clsList) {
                Annotation annotation = cls.getAnnotation(AuroraAction.class);
                if (annotation == null) {
                    continue;
                }
                AuroraAction cicadaAction = (AuroraAction) annotation;
                actionMap.put(StringUtils.isBlank(cicadaAction.value()) ? cls.getName() : cicadaAction.value(), cls);

            }
        }
        return actionMap;
    }

    /**
     * 获取所有@Interceptor注解的类
     * @param packageName 包名
     * @return 注解类映射
     */
    public static Map<Class<?>, Integer> getAuroraInterceptor(String packageName) {

        if (interceptorMap == null) {
            Set<Class<?>> clsList = getClasses(packageName);

            if (clsList == null || clsList.isEmpty()) {
                return interceptorMap;
            }

            interceptorMap = new HashMap<>(16);
            for (Class<?> cls : clsList) {
                Annotation annotation = cls.getAnnotation(Interceptor.class);
                if (annotation == null) {
                    continue;
                }
                Interceptor interceptor = (Interceptor) annotation;
                interceptorMap.put(cls, interceptor.order());
            }
        }
        return interceptorMap;
    }

    /**
     * 获取bean工厂
     */
    public static AuroraBeanFactory getAuroraBeanFactory(String packageName) throws Exception {
        if (CollectionUtils.isEmpty(beanFactoryList)) {
            Set<Class<?>> clsList = getClasses(packageName);

            if (!CollectionUtils.isEmpty(clsList)) {
                beanFactoryList = new HashSet<>(1);
                for (Class<?> cls : clsList) {
                    if (CollectionUtils.isEmpty(cls.getInterfaces())){
                        continue;
                    }
                    if (!CollectionUtils.contains(cls.getInterfaces(), AuroraBeanFactory.class)){
                        continue;
                    }
                    beanFactoryList.add((AuroraBeanFactory) cls.newInstance());
                }
            }
        }
        return beanFactoryList.iterator().next();
    }
}
